package com.cskaoyan.wordmemorize.task;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cskaoyan.wordmemorize.auth.StpKit;
import com.cskaoyan.wordmemorize.dao.entity.*;
import com.cskaoyan.wordmemorize.dao.mapper.*;
import com.cskaoyan.wordmemorize.service.UserService;
import com.cskaoyan.wordmemorize.sms.SmsDelayMessage;
import com.cskaoyan.wordmemorize.sms.SmsSender;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.DelayQueue;
import java.util.stream.Collectors;

@Component
@EnableScheduling
@Slf4j
public class UserMessageRemindTask {

    // 延迟队列
    @Resource
    DelayQueue<SmsDelayMessage> delayQueue;

    // 消息发送工具类对象
    @Resource
    SmsSender smsSender;

    // mapper用来在发送短信后，插入发送短信的记录
    @Resource
    UserRemindMessageMapper userRemindMessageMapper;

    @Resource
    UserRemindMapper userRemindMapper;

    @Autowired
    UserCheckinMapper userCheckinMapper;

    @Autowired
    UserMapper userMapper;

    @Autowired
    UserRevStatisticsMapper userRevStatisticsMapper;

    @Value("${user.remind.days}")
    Integer ContinuousCheckInDays;

    @Value("${user.remind.span}")
    Integer CheckInSpan;

    /**
     这里@PstConstruct注解的作用为，让Spring在创建完对象后，自动调用该方法
     来完成对象的初始化(也就是说该方法会被Spring自动调用)
     */
    @PostConstruct
    public void init() {
        log.info("start to consume message...");

        // 启动线程(也可以自己查阅资料使用其他方式启动线程)
        new Thread(() -> {
            while (true) {
                // 获取延迟队列中的短信消息对象(注意如果没有或者队头元素延迟时间未到会在这里阻塞)
                SmsDelayMessage smsDelayMessage = null;
                try {
                    smsDelayMessage = delayQueue.take();
                    System.out.println(smsDelayMessage);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                // 获取到短信消息后，发送
                smsSender.sendRemindMessage(smsDelayMessage.getUserName(), smsDelayMessage.getVocCount(), smsDelayMessage.getPhoneNumber());
                // 在数据库添加消息发送记录
                UserRemindMessageDO userRemindMessageDO = new UserRemindMessageDO();
                userRemindMessageDO.setUserId(smsDelayMessage.getUserId());
                userRemindMessageDO.setPhoneNumber(smsDelayMessage.getPhoneNumber());
                userRemindMessageDO.setSendDate(LocalDate.now());
                userRemindMessageMapper.insert(userRemindMessageDO);
            }
        }).start();
    }

    // @Scheduled(cron = "0 23 0/1 * * ?")      // 每小时的整点运行一次，但这里为了方便测试，使用接口来调用，而不是定时执行
    public void initialize() {
        log.info("start to message remind....");
        // 当前整点（00 分 00 秒）
        LocalDateTime now = LocalDateTime.now()
                .withSecond(0)
                .withNano(0);

        // 下一整点之前 1 秒  →  59 分 59 秒
        LocalDateTime end = now
                .plusHours(1)
                .minusSeconds(1);
        int i = 1;
        int size = 100;
        while (true){
            // 用户已开启消息提醒，且设置的提醒时间在未来的一小时内(包括整点的那一分钟)
            Page<UserRemindDO> page = new Page<>(i, size);
            LambdaQueryWrapper<UserRemindDO> userRemindQueryWrapper = new LambdaQueryWrapper<>();
            userRemindQueryWrapper
                    .eq(UserRemindDO::getMessageStatus, 1)
                    .ge(UserRemindDO::getRemindTime, now.toLocalTime())
                    .le(UserRemindDO::getRemindTime, end.toLocalTime());
            Page<UserRemindDO> userRemindDOPage = userRemindMapper.selectPage(page, userRemindQueryWrapper);
            List<UserRemindDO> userRemindDOS = userRemindDOPage.getRecords();
            if (CollectionUtils.isEmpty(userRemindDOS))
                break;

            userRemindDOS.stream()
                    .filter(userRemindDO -> {
                        // 用户今天尚未签到
                        Long userId = userRemindDO.getUserId();
                        LambdaQueryWrapper<UserCheckinDO> queryWrapper = new LambdaQueryWrapper<>();
                        queryWrapper.eq(UserCheckinDO::getUserId, userId)
                                .eq(UserCheckinDO::getSignDate, LocalDate.now());
                        UserCheckinDO userCheckinDO = userCheckinMapper.selectOne(queryWrapper);
                        return userCheckinDO == null;
                    })
                    .filter(userRemindDO -> {
                        // 用户最近连续签到天数>=指定天数(在配置文件中指定，默认3天)
                        Long userId = userRemindDO.getUserId();
                        List<Long> continuousCheckInSpan = userCheckinMapper.getContinuousCheckInSpan(userId, ContinuousCheckInDays, CheckInSpan);
                        return !CollectionUtils.isEmpty(continuousCheckInSpan);
                    })
                    .filter(userRemindDO -> {
                        // 用户最近一个周内没有发送过提醒短信(控制短信发送频率)
                        Long userId = userRemindDO.getUserId();
                        LambdaQueryWrapper<UserRemindMessageDO> queryWrapper = new LambdaQueryWrapper<>();
                        queryWrapper.eq(UserRemindMessageDO::getUserId, userId)
                                .between(UserRemindMessageDO::getSendDate, LocalDate.now().minusDays(6), LocalDate.now());
                        List<UserRemindMessageDO> userRemindMessageDOS = userRemindMessageMapper.selectList(queryWrapper);
                        return CollectionUtils.isEmpty(userRemindMessageDOS);
                    })
                    .forEach(userRemindDO -> {
                        Long userId = userRemindDO.getUserId();
                        UserDO userDO = userMapper.selectById(userId);
                        Integer vocCountOfDay = userDO.getVocCountOfDay();

                        LambdaQueryWrapper<UserRevStatisticsDO> queryWrapper = new LambdaQueryWrapper<>();
                        queryWrapper.eq(UserRevStatisticsDO::getUserId, userId)
                                .eq(UserRevStatisticsDO::getReviewDate, LocalDate.now());
                        UserRevStatisticsDO userRevStatisticsDO = userRevStatisticsMapper.selectOne(queryWrapper);
                        Integer totalRevCount = 0;
                        if (userRevStatisticsDO != null){
                            totalRevCount = userRevStatisticsDO.getTotalCount();
                        }
                        Integer remindCount = vocCountOfDay - totalRevCount;
                        if (remindCount > 0){
                            SmsDelayMessage smsDelayMessage = new SmsDelayMessage();
                            smsDelayMessage.setUserId(userId);
                            smsDelayMessage.setUserName(userRemindDO.getUserName());
                            String phoneNumber = userRemindDO.getPhoneNumber();
                            String postPhoneNumber = phoneNumber;
                            if (phoneNumber.startsWith("+86-")){
                                postPhoneNumber = phoneNumber.substring(4);
                            }
                            smsDelayMessage.setPhoneNumber(postPhoneNumber);
                            smsDelayMessage.setVocCount(remindCount);
                            smsDelayMessage.setRemindTime(userRemindDO.getRemindTime());
                            System.out.println("smsDelayMessage = " + smsDelayMessage);
                            delayQueue.offer(smsDelayMessage);
                        }
                    });
            i++;
        }

        log.info("end message remind....");
    }
}
